package captcha

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/wenlng/go-captcha-assets/resources/images"
	"github.com/wenlng/go-captcha-assets/resources/shapes"
	"github.com/wenlng/go-captcha/v2/base/option"
	"github.com/wenlng/go-captcha/v2/click"
	"product/authorization/serve/internal/svc"
	"product/authorization/serve/internal/types"
	"product/common/encryption"

	"github.com/zeromicro/go-zero/core/logx"
)

type CreateShapeCaptchaLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// NewCreateShapeCaptchaLogic 生成形状验证码
func NewCreateShapeCaptchaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateShapeCaptchaLogic {
	return &CreateShapeCaptchaLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *CreateShapeCaptchaLogic) CreateShapeCaptcha() (resp *types.ShapeCaptchaResp, err error) {
	builder, err := initShapeCaptcha()
	if err != nil {
		return &types.ShapeCaptchaResp{Ok: false}, err
	}
	captchaData, err := builder.Generate()
	if err != nil {
		return &types.ShapeCaptchaResp{Ok: false}, err
	}
	dotData := captchaData.GetData()
	if dotData == nil {
		return &types.ShapeCaptchaResp{Ok: false}, errors.New("验证码生成失败")
	}
	var imageBase64, thumbBase64 string
	imageBase64, err = captchaData.GetMasterImage().ToBase64()
	if err != nil {
		return &types.ShapeCaptchaResp{Ok: false}, err
	}
	thumbBase64, err = captchaData.GetThumbImage().ToBase64()
	if thumbBase64 == "" {
		return &types.ShapeCaptchaResp{Ok: false}, errors.New("缩略图生成失败")
	}
	dotsByteJson, _ := json.Marshal(dotData)
	key := encryption.Md5ByBytes(dotsByteJson)
	_ = l.svcCtx.Redis.SetexCtx(l.ctx, key, string(dotsByteJson), 60)
	return &types.ShapeCaptchaResp{
		CaptchaBase64Image:     imageBase64,
		CaptchCheckBase64Image: thumbBase64,
		CaptchaKey:             key,
		Ok:                     true,
	}, nil
}

func initShapeCaptcha() (click.Captcha, error) {
	shapeBuilder := click.NewBuilder(click.WithRangeLen(option.RangeVal{Min: 3, Max: 6}),
		click.WithRangeVerifyLen(option.RangeVal{Min: 2, Max: 3}),
		click.WithRangeThumbBgDistort(option.DistortLevel1),
		click.WithIsThumbNonDeformAbility(true))
	shapeMaps, err := shapes.GetShapes()
	if err != nil {
		return nil, err
	}
	images, err := images.GetImages()
	if err != nil {
		return nil, err
	}
	shapeBuilder.SetResources(
		click.WithBackgrounds(images),
		click.WithShapes(shapeMaps))
	return shapeBuilder.MakeWithShape(), nil
}
